package com.example.smartlight.utils;

import ohos.ai.asr.AsrClient;
import ohos.ai.asr.AsrIntent;
import ohos.ai.asr.AsrListener;
import ohos.ai.asr.util.AsrError;
import ohos.ai.asr.util.AsrResultKey;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.audio.AudioStreamInfo;
import ohos.utils.PacMap;
import ohos.utils.zson.ZSONObject;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AsrUtils {
    private static final HiLogLabel TAG = new HiLogLabel(3, 0xD001100, AsrUtils.class.getName());
    //采样率限定16000HZ
    private static final int VIDEO_SAMPLE_RATE = 16000;
    private static final int VAD_END_WAIT_MS = 2000;
    private static final int VAD_FRONT_WAIT_MS = 4800;
    private static final int TIMEOUT_DURATION = 20000;

    private static final int CAPACITY = 6;
    private static final int ALIVE_TIME = 3;
    private static final int BYTES_LENGTH = 1280;
    private static final int POOL_SIZE = 3;

    /*
     **  错误：-1
     **  初始：0
     **  init:1
     **  开始输入:2
     **  结束输入:3
     **  识别结束:5
     **  中途出识别结果:9
     **  最终识别结果：10
     */
    public int state = 0;
    //识别结果
    public String result;
    boolean isStarted = false;

    private AsrClient asrClient;
    private AsrListener listener;
    AsrIntent asrIntent;
    private AudioCaptureUtils audioCaptureUtils;

    //录音线程
    private ThreadPoolExecutor poolExecutor;

    public AsrUtils(Context context) {
        this.audioCaptureUtils = new AudioCaptureUtils(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO, VIDEO_SAMPLE_RATE);
        this.audioCaptureUtils.init("com.example.aisperec");
        this.result = "";
        //给录音控件初始化一个新的线程池
        poolExecutor = new ThreadPoolExecutor(
                POOL_SIZE,
                POOL_SIZE,
                ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(CAPACITY),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        if (asrIntent == null) {
            asrIntent = new AsrIntent();
            asrIntent.setAudioSourceType(AsrIntent.AsrAudioSrcType.ASR_SRC_TYPE_PCM);
            asrIntent.setVadEndWaitMs(VAD_END_WAIT_MS);
            asrIntent.setVadFrontWaitMs(VAD_FRONT_WAIT_MS);
            asrIntent.setTimeoutThresholdMs(TIMEOUT_DURATION);
        }

        if (asrClient == null) {
            asrClient = AsrClient.createAsrClient(context).orElse(null);
        }
        if (listener == null) {
            listener = new MyAsrListener();
            this.asrClient.init(asrIntent, listener);
        }

    }


    public void start() {
        if (!this.isStarted) {
            this.isStarted = true;
            asrClient.startListening(asrIntent);
            poolExecutor.submit(new AudioCaptureRunnable());
        }
    }

    public void stop() {
        this.isStarted = false;
        asrClient.stopListening();
        audioCaptureUtils.stop();
    }

    public String getResult() {
        return result;
    }

    public String getResultAndClear() {
        if (this.result == "")
            return "";
        String results = getResult();
        this.result = "";
        return results;
    }

    public void setAsrIntent(AsrIntent asrIntent) {
        this.asrIntent = asrIntent;
    }


    public void destroy() {
        this.asrClient.destroy();
        poolExecutor.shutdown();
        this.audioCaptureUtils.destory();
    }

    //音频录制
    private class AudioCaptureRunnable implements Runnable {
        @Override
        public void run() {
            byte[] buffers = new byte[BYTES_LENGTH];
            audioCaptureUtils.start();
            while (isStarted) {
                int ret = audioCaptureUtils.read(buffers, 0, BYTES_LENGTH);
                if (ret <= 0) {
                    HiLog.error(TAG, "======Error read data");
                } else {
                    asrClient.writePcm(buffers, BYTES_LENGTH);
                }
            }
        }
    }


    public class MyAsrListener implements AsrListener {

        @Override
        public void onInit(PacMap pacMap) {
            HiLog.info(TAG, "====== init");
            state = 1;
            System.out.println("初始化");
        }

        @Override
        public void onBeginningOfSpeech() {
            state = 2;
            System.out.println("开始说话");
        }

        @Override
        public void onRmsChanged(float v) {

        }

        @Override
        public void onBufferReceived(byte[] bytes) {

        }

        @Override
        public void onEndOfSpeech() {
            state = 3;
            System.out.println("停止说话");
        }

        @Override
        public void onError(int i) {

            state = -1;
            if (i == AsrError.ERROR_SPEECH_TIMEOUT) {
                asrClient.startListening(asrIntent);
            } else {
                String result = "onError code :" +i ;
                asrClient.stopListening();
            }
        }

        @Override
        public void onResults(PacMap pacMap) {
            state = 10;
            String results = pacMap.getString(AsrResultKey.RESULTS_RECOGNITION);
            ZSONObject zsonObject = ZSONObject.stringToZSON(results);
            ZSONObject infoObject;
            if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
                infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
                String resultWord = infoObject.getString("ori_word").replace(" ", "");
                result += resultWord;
            }
            System.out.println("检测结果");
        }

        @Override
        public void onIntermediateResults(PacMap pacMap) {
            state = 9;
//            String result = pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE);
//            if (result == null)
//                return;
//            ZSONObject zsonObject = ZSONObject.stringToZSON(result);
//            ZSONObject infoObject;
//            if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
//                infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
//                String resultWord = infoObject.getString("ori_word").replace(" ", "");
//                HiLog.info(TAG, "=========== 9 " + resultWord);
//            }
        }

        @Override
        public void onEnd() {
            state = 5;
            if (isStarted)
                asrClient.startListening(asrIntent);
        }

        @Override
        public void onEvent(int i, PacMap pacMap) {

        }

        @Override
        public void onAudioStart() {
            state = 2;

        }

        @Override
        public void onAudioEnd() {
            state = 3;
        }
    }
}
